package online.heycm.rbac.domain.user;

import java.util.Set;
import java.util.UUID;
import online.heycm.platform.common.entity.result.Optional;
import online.heycm.platform.redis.RedisCache;
import online.heycm.rbac.common.cache.ParamCfgCache;
import online.heycm.rbac.common.cache.RoleCache;
import online.heycm.rbac.common.constant.ErrorCode;
import online.heycm.rbac.common.constant.ParamCfg;
import online.heycm.rbac.common.entity.Session;
import online.heycm.rbac.common.type.AuthType;
import online.heycm.rbac.common.utils.Md5Util;
import online.heycm.rbac.common.utils.SessionUtil;
import online.heycm.rbac.domain.basic.repository.entity.BasicRbacRole;
import online.heycm.rbac.domain.user.aggregate.ConsoleUser;
import online.heycm.rbac.domain.user.repository.UserRepository;
import online.heycm.rbac.domain.user.repository.entity.UserAuthorize;
import online.heycm.rbac.domain.user.repository.entity.UserProfile;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * 认证器
 *
 * @author hey
 * @version 1.0
 * @date 2024/1/11 17:30
 */
@Component
public class Authenticator {

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private ParamCfgCache paramCfgCache;

    @Autowired
    private UserRepository userRepository;

    public Optional<String> createToken(Session session) {
        long expire = Long.parseLong(paramCfgCache.getCache(ParamCfg.SESSION_EXPIRE)) * 1000;
        String token = UUID.randomUUID().toString().replaceAll("-", "");
        session.setToken(token);
        Optional optional = SessionUtil.saveSession(expire, session, redisCache);
        if (optional.fail()) {
            return optional;
        }
        return Optional.of(token);
    }

    public Optional expire(Session session) {
        return SessionUtil.expire(session, redisCache);
    }

    /**
     * 登录后更新认证信息
     *
     * @param userAuthorize 用户认证信息
     * @return
     */
    public void updateAuthorize(UserAuthorize userAuthorize) {
        UserAuthorize update = new UserAuthorize();
        update.setUserId(userAuthorize.getUserId());
        update.setAuthType(userAuthorize.getAuthType());
        update.setAuthToken(userAuthorize.getAuthToken());
        update.setLoginTime(userAuthorize.getLoginTime());
        userRepository.updateAuthorizeById(update);
    }

    /**
     * 账密认证
     *
     * @param authIdentifier 账户
     * @param authCredential 密码
     * @return
     */
    public Optional<Session> account(String authIdentifier, String authCredential) {
        // 获取认证信息
        Optional<UserAuthorize> optional = userRepository.queryAuthorize(AuthType.ACCOUNT.getType(), authIdentifier);
        if (optional.fail()) {
            return Optional.error(ErrorCode.CONSOLE_LOGIN);
        }
        UserAuthorize userAuthorize = optional.get();
        // 密码校验
        authCredential = Md5Util.encrypt(authCredential, userAuthorize.getAuthSalt());
        if (!userAuthorize.getAuthCredential().equals(authCredential)) {
            return Optional.error(ErrorCode.CONSOLE_LOGIN);
        }
        // 获取用户基本信息
        Optional<UserProfile> profile = userRepository.queryProfile(userAuthorize.getUserId());
        if (profile.fail()) {
            return Optional.error(ErrorCode.CONSOLE_LOGIN);
        }
        ConsoleUser consoleUser = new ConsoleUser(profile.get(), userAuthorize);
        Set<Integer> roleIds = userRepository.queryRole(consoleUser.getUserId());
        for (BasicRbacRole role : RoleCache.getByIds(roleIds)) {
            consoleUser.addRole(role);
        }
        // 创建并存储Session
        Session session = consoleUser.createSession();
        createToken(session);
        // 更新认证信息
        userAuthorize.setAuthToken(session.getToken());
        userAuthorize.setLoginTime(session.getLoginTime());
        updateAuthorize(userAuthorize);
        return Optional.of(session);
    }

    /**
     * 短信认证
     *
     * @param authIdentifier 手机
     * @param authCredential 短信
     * @return
     */
    public Optional<Session> sms(String authIdentifier, String authCredential) {
        return Optional.error(ErrorCode.LOGIN_AUTH_TYPE);
    }
}
